package com.kalua.list.searchengine;

import java.io.IOException;
import java.util.Map;
import java.util.Set;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MultiPhraseQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.kalua.list.dbaccess.product.ProductDAO;
import com.kalua.list.domainmodel.NumericId;
import com.kalua.list.domainmodel.TextIdentifier;
import com.kalua.list.domainmodel.product.Product;

public class Start {

	private static final Logger logger = LoggerFactory.getLogger(Start.class);	
	
	
	private static final String SPRING_CTX_NAME = "search-engine-ctx.xml";
	
	public static void main(String[] args) {

		try (ClassPathXmlApplicationContext context = 
				new ClassPathXmlApplicationContext(SPRING_CTX_NAME)) {
				ProductDAO productDAO = context.getBean("productDAO", ProductDAO.class);
								
				Directory indexDir = new RAMDirectory();//FSDirectory.open(Paths.get(indexOutput.getAbsolutePath()));
				Analyzer analyzer = new StandardAnalyzer();
				IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
				iwc.setOpenMode(OpenMode.CREATE);
				
				IndexWriter writer = new IndexWriter(indexDir, iwc);
				indexProducts(productDAO, writer);				
				writer.close();
				
				logger.info("Generated Indexes, starting search.");
				
				IndexReader reader = DirectoryReader.open(indexDir);
				IndexSearcher searcher = new IndexSearcher(reader);
				
				MultiPhraseQuery query = new MultiPhraseQuery();
				query.add(new Term("name", "eggs"));
				int pageSize = 100;
				TopDocs searchResults = searcher.search(query, pageSize);
				ScoreDoc[] hits = searchResults.scoreDocs;
				int numTotalHits = searchResults.totalHits;
				
				logger.info("Query completed. Found {} possible hits.", numTotalHits);				
				int start = 0;
				int end = Math.min(numTotalHits, pageSize);
				while (end <= hits.length) {
					for (int i=start;i<end;i++) {
						Document doc = searcher.doc(hits[i].doc);
						String name = doc.get("name");
						String productId = doc.get("productId");
						IndexableField[] classifications = doc.getFields("classification");
						
PRINT OUT RESULTS
					}
				}
				reader.close();
				
				
		} catch (Exception exce) {
			logger.error("Search engine bailed out with imexpected exception.", exce);
		} 
	}

	private static Map<NumericId, Product> 
								indexProducts(	ProductDAO productDAO,
														IndexWriter writer) 
														throws IOException {
		Map<NumericId, Product> products = 
				productDAO.findByRetailerId(new TextIdentifier("TESCO"));
		Document productDoc;
		for (Product product : products.values()) {
			productDoc = toDocument(product);
			writer.addDocument(productDoc);
		}
		return products;
	}

	protected static Document toDocument(Product product) {
		Document result;
		result = new Document();
		Set<String> classifications = product.getClassifications();
		for (String classification : classifications) {
			result.add(new TextField( "classification", 
													classification, TextField.Store.YES));
		}
		result.add(new TextField("name", product.getName(), 
												TextField.Store.YES));
		result.add(new TextField("retailer", product.getRetailerId().getValue(), 
												TextField.Store.YES));
		result.add(new TextField("productId", product.getId().getValue().toString(), 
												TextField.Store.YES));
		
		return result;
	}		 
}